/* Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * This file is a part of the CANN Open Software.
 * Licensed under CANN Open Software License Agreement Version 1.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 * ===================================================================================================================*/

#ifndef GRAPH_EXPRESSION_H_
#define GRAPH_EXPRESSION_H_

#include <memory>
#include <limits>
#include <string>
#include <vector>
#include <map>
#include <array>
#include "graph/ge_error_codes.h"

namespace ge {
namespace expression {
class Expression;
using ExpressionPtr = std::shared_ptr<Expression>;

class ExpressionImpl;
using ExpressionImplPtr = std::shared_ptr<ExpressionImpl>;

enum ExprType : size_t {
  EXPR_CONSTANT = 0,
  EXPR_VARIABLE,
  EXPR_OPERATION,
  EXPR_NONE = std::numeric_limits<size_t>::max()
};

enum StrType : size_t {
  STR_CPP = 0,
};

class Expression {
 public:
  /**
   * @brief 创建常量
   */
  static ExpressionPtr CreateExpression(const int32_t const_value, const std::string &name = "");
  static ExpressionPtr CreateExpression(const int64_t const_value, const std::string &name = "");
  static ExpressionPtr CreateExpression(const uint32_t const_value, const std::string &name = "");
  static ExpressionPtr CreateExpression(const uint64_t const_value, const std::string &name = "");
  static ExpressionPtr CreateExpression(const double const_value, const std::string &name = "");
  /**
   * @brief 创建变量
   */
  static ExpressionPtr CreateExpression(const std::string &name);
  virtual ~Expression();

  Expression(const Expression&) = delete;
  Expression(Expression&&) = delete;
  Expression &operator=(const Expression&) = delete;
  Expression &operator=(Expression&&) = delete;
  /**
   * @brief 将表达式转换成字符串
   */
  std::string Str(const StrType type = StrType::STR_CPP) const;
  /**
   * @brief 获取表达式的类型
   */
  ExprType GetExprType() const;
  /**
   * @brief 对当前表达式中的表达式进行替换，例如 y= x+2. y.replace({x, 2*x}) -> y = 2*x + 2
   *        注意当前symengine对div sub的表达式替换能力有缺失，需要用户自己保证，例如x/y*z->Replace({{x/y, m}})会替换失败
   * @param map<Expr, Epxr> key被替换的表达式，value待替换的表达式
   */
  ExpressionPtr Replace(const std::map<ExpressionPtr, ExpressionPtr> &replace_vars) const;
  /**
   * @brief 对当前表达式进行化简。例如2+x+4 -> 6+x
   */
  ExpressionPtr Simplify() const;
  /**
   * @brief 判断当前表达式字符串中是否含有表达式e的子字符串，例如max((x+2), (4*y)) 含有 x和y
   */
  bool ContainVar(const ExpressionPtr &e) const;
  /**
   * @brief 判断两个Expr是否相等
   */
  bool operator==(const Expression &e) const;
  bool Eq(const ExpressionPtr &e) const;
  /**
   * @brief 获取表达式最基础的元素。例如x - (y * z)，返回{x, y, z}, 注意该接口没有依据字符去重
   */
  std::vector<ExpressionPtr> GetPrimaryArgs() const;
  /**
   * @brief 获取表达式的值
   */
  graphStatus GetResult(const std::map<ExpressionPtr, ExpressionPtr> &vars_value, double &result) const;
  /**
   * @brief 获取const&&var的名字，operation的名字为空
   */
  std::string GetName() const;

  friend ExpressionPtr Add(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Sub(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Mul(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Div(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Max(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Min(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Pow(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Log(const ExpressionPtr &a);  // 默认以E为底
  friend ExpressionPtr Log(const ExpressionPtr &a, const ExpressionPtr &b);
  friend ExpressionPtr Rational(const int32_t a, const int32_t b);  // 分数
  friend ExpressionPtr Ceiling(const ExpressionPtr &a);
  friend std::ostream &operator<<(std::ostream &os, const Expression &e);
 private:
  static ExpressionPtr CreateExpression(const ExpressionImplPtr &e);
  template <typename T>
  static ExpressionPtr CreateExpressionInner(T value, const std::string &name);
  explicit Expression(const ExpressionImplPtr &e);
  ExpressionImplPtr impl_;
  std::string name_;
};

ExpressionPtr operator+(const ExpressionPtr &e1, const ExpressionPtr &e2);
ExpressionPtr operator-(const ExpressionPtr &e1, const ExpressionPtr &e2);
ExpressionPtr operator*(const ExpressionPtr &e1, const ExpressionPtr &e2);
ExpressionPtr operator/(const ExpressionPtr &e1, const ExpressionPtr &e2);
ExpressionPtr Add(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Sub(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Mul(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Div(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Max(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Min(const ExpressionPtr &a, const ExpressionPtr &b);
ExpressionPtr Pow(const ExpressionPtr &base, const ExpressionPtr &arg);
ExpressionPtr Log(const ExpressionPtr &arg);  // 默认以E为底
ExpressionPtr Log(const ExpressionPtr &base, const ExpressionPtr &arg);
ExpressionPtr Rational(const int32_t, const int32_t);  // 分数
ExpressionPtr Ceiling(const ExpressionPtr &a);
std::ostream &operator<<(std::ostream &os, const Expression &e);
}  // namepsace expression
}  // namepsace ge
#endif  // ATTT_BASIC_EXPR_H_